#ifndef __VOL_GOOGLE_V8
#define __VOL_GOOGLE_V8

#include "v8.h"
#include "libplatform\libplatform.h"
#include "vol_google_v8_rc.h"

using namespace v8;

#ifdef _VOL_X64
	#define _VOL_VINT_PROCESSOR  argvs[npParamIndex] = BigInt::New(context->GetIsolate(), (int64_t)va_arg (argList, INT_P));
#else
	#define _VOL_VINT_PROCESSOR  argvs[npParamIndex] = Int32::New(context->GetIsolate(), (int32_t)va_arg (argList, INT_P));
#endif

#define DECLARE_V8_INVOKE_EXTEND_PARAM(first_extend_param, call)                                              \
	const INT_P npNumParams = _tcslen (szParamType) - first_extend_param;                                     \
    ASSERT (npNumParams > 0);                                                                                 \
    const TCHAR* szParamTypes = szParamType + first_extend_param;                                             \
	va_list argList;                                                                                          \
	Local<Value>* argvs = new Local<Value>[npNumParams];                                                      \
	va_start (argList, context);                                                                              \
	for (UINT npParamIndex = 0; npParamIndex < npNumParams; npParamIndex++)                                   \
	{ 																										  \
		switch (szParamTypes [npParamIndex])                                                                  \
		{                                                                                                     \
			case _C_VOL_SBYTE:                                                                                \
				argvs[npParamIndex] = Int32::New(context->GetIsolate(), (int32_t)va_arg (argList, S_BYTE));   \
				break;                                                                                        \
			case _C_VOL_SHORT:                                                                                \
				argvs[npParamIndex] = Int32::New(context->GetIsolate(), (int32_t)va_arg (argList, SHORT));    \
				break;                                                                                        \
			case _C_VOL_WCHAR:                                                                                \
				argvs[npParamIndex] = Int32::New(context->GetIsolate(), (int32_t)va_arg (argList, TCHAR));    \
				break;                                                                                        \
			case _C_VOL_INT:                                                                                  \
				argvs[npParamIndex] = Int32::New(context->GetIsolate(), (int32_t)va_arg (argList, INT));      \
				break;                                                                                        \
			case _C_VOL_VINT:                                                                                 \
				_VOL_VINT_PROCESSOR                                                                           \
				break;                                                                                        \
			case _C_VOL_LONG:                                                                                 \
				argvs[npParamIndex] = BigInt::New(context->GetIsolate(), (int64_t)va_arg (argList, INT64));   \
				break;                                                                                        \
			case _C_VOL_FLOAT:                                                                                \
				argvs[npParamIndex] = Number::New(context->GetIsolate(), (FLOAT)va_arg (argList, DOUBLE));    \
				break;                                                                                        \
			case _C_VOL_DOUBLE:                                                                               \
				argvs[npParamIndex] = Number::New(context->GetIsolate(), va_arg (argList, DOUBLE));           \
				break;                                                                                        \
			case _C_VOL_BOOL:                                                                                 \
				argvs[npParamIndex] = Boolean::New(context->GetIsolate(), va_arg (argList, BOOL));            \
				break;                                                                                        \
			case _C_VOL_STRING:                                                                               \
				argvs[npParamIndex] = String::NewFromUtf8(context->GetIsolate(), CU8String(va_arg (argList, const TCHAR*)).GetText()).ToLocalChecked();    \
				break;                                                                                        \
			default:  { ASSERT(FALSE); }                                                                      \
		}                                                                                                     \
	}                                                                                                         \
	va_end(argList);                                                                                          \
	call;                                                                                                     \
	delete[] argvs;                                                                                           \
	return ret;

class CV8PlatformWrapper
{
	private:
		std::unique_ptr<Platform> m_platform;
		
	public:
		CV8PlatformWrapper();
		~CV8PlatformWrapper();
		void CreatePlatform(int thread_pool_size = 0, BOOL idle_task_support = FALSE, BOOL in_process_stack_dumping = FALSE);
		Platform* GetPlatform();
};

class CV8IsolateWrapper
{
	class IsolateWrapper
	{
		public:
			HandleScope m_HandleScope;
			Isolate::Scope m_Scope;
		public:
			inline_ IsolateWrapper(Isolate* pIsolate):m_HandleScope(pIsolate),m_Scope(pIsolate) {}
			inline_ ~IsolateWrapper(){}
	};
	
	private:
		Isolate* m_isolate;
		IsolateWrapper* pWrapper;
		BOOL autoDestroyIsolate;
	public:
		CV8IsolateWrapper();
		~CV8IsolateWrapper();
		void CreateIsolate(Isolate::CreateParams& stParams);
		void CreateIsolateWithoutWrapper(Isolate* pIsolate);
		Isolate* GetIsolate();
		HandleScope& GetHandleScope();
		Isolate::Scope& GetScope();
		void DestroyIsolate();
};

class CV8ContextWrapper
{
	class LocalContextWrapper
	{
		public:
			Local<Context> m_Context;
			Context::Scope m_Scope;
		public:
			inline_ LocalContextWrapper(Isolate* pIsolate):m_Context(Context::New(pIsolate)),m_Scope(m_Context) {}
			inline_ LocalContextWrapper(const Local<Context>& context):m_Context(context),m_Scope(m_Context) {}
			inline_ ~LocalContextWrapper(){}
	};
	
	private:
		LocalContextWrapper* pWrapper;

	public:
		inline_ CV8ContextWrapper() { pWrapper = NULL; }
		inline_ ~CV8ContextWrapper() { DestroyWrapper(); }
		
		inline_ void CreateContext(Isolate* pIsolate) { if (pWrapper == NULL) pWrapper = new LocalContextWrapper(pIsolate); }
		inline_ void CreateContext(const Local<Context>& context) { if (pWrapper == NULL) pWrapper = new LocalContextWrapper(context); }

		inline_ Local<Context>& GetLocalContext()
		{
			ASSERT(pWrapper != NULL);
			return pWrapper->m_Context;
		}
		inline_ Context* GetContextPtr()
		{
			ASSERT(pWrapper != NULL);
			return *pWrapper->m_Context;
		}
		
		inline_ void DestroyWrapper() { if (pWrapper != NULL) delete pWrapper; }
};

template <class T>
class CV8WrapperTemplate
{
	class LocalWrapper
	{
		public:
			Local<T> m_Value;
		public:
			inline_ LocalWrapper(Local<T>& value):m_Value(value) {}
			inline_ ~LocalWrapper(){}
	};
	private:
		LocalWrapper* pWrapper;

	public:
		inline_ CV8WrapperTemplate() { pWrapper = NULL; }
		inline_ ~CV8WrapperTemplate() { DestroyWrapper(); }
		
		inline_ void CreateValue(Local<T>& value) { if (pWrapper == NULL) pWrapper = new LocalWrapper(value); }
		inline_ void CreateValue(MaybeLocal<T>& value) { return CreateValue(value.ToLocalChecked()); }

		inline_ Local<T>& ReplaceValue(Local<T>& value)
		{
			if (pWrapper != NULL)
				DestroyWrapper();
			CreateValue(value);
			return GetLocalValue();
		}
		inline_ Local<T>& ReplaceValue(MaybeLocal<T>& value) { return ReplaceValue(value.ToLocalChecked()); }
		
		inline_ Local<T>& GetLocalValue()
		{
			if (pWrapper == NULL)	//Local数据尚未建立?
				CreateValue(Local<T>());
			return pWrapper->m_Value;
		}
		inline_ T& GetValue()
		{
			ASSERT(pWrapper != NULL);
			return **pWrapper->m_Value;
		}
		inline_ T* GetValuePtr()
		{
			ASSERT(pWrapper != NULL);
			return *pWrapper->m_Value;
		}
		
		inline_ void DestroyWrapper() 
		{ 
			if (pWrapper != NULL) 
				delete pWrapper; 
			pWrapper = NULL;
		}
		
		MaybeLocal<Value> CallAsConstructor(const TCHAR* szParamType, Local<Context> context, ...)
		{
			DECLARE_V8_INVOKE_EXTEND_PARAM(1, MaybeLocal<Value> ret = GetLocalValue()->CallAsConstructor(context, (INT)npNumParams, argvs))
		}
		MaybeLocal<Value> CallAsFunction(const TCHAR* szParamType, Local<Context> context, Local<Value> recv, ...)
		{
			DECLARE_V8_INVOKE_EXTEND_PARAM(2, MaybeLocal<Value> ret = GetLocalValue()->CallAsFunction(context, recv, (INT)npNumParams, argvs))
		}
		
		MaybeLocal<Value> Call(const TCHAR* szParamType, Local<Context> context, Local<Value> recv, ...)
		{
			DECLARE_V8_INVOKE_EXTEND_PARAM(2, MaybeLocal<Value> ret = data().GetLocalValue()->Call(context, recv, (INT)npNumParams, argvs))
		}
		MaybeLocal<Value> NewInstance(const TCHAR* szParamType, Local<Context> context, ...)
		{
			DECLARE_V8_INVOKE_EXTEND_PARAM(1, MaybeLocal<Object> ret = data().GetLocalValue()->NewInstance(context, (INT)npNumParams, argvs))
		}
};

template <class T>
class CV8ReturnValueWrapperTemplate
{
	class ObjectWrapper
	{
		public:
			ReturnValue<T> m_Value;
		public:
			inline_ ObjectWrapper(const ReturnValue<T>& that):m_Value(that) {}
			inline_ ~ObjectWrapper(){}
	};
	
	private:
		ObjectWrapper* pWrapper;

	public:
		inline_ CV8ReturnValueWrapperTemplate() { pWrapper = NULL; }
		inline_ ~CV8ReturnValueWrapperTemplate() { DestroyWrapper(); }
		
		inline_ void CreateValue(ReturnValue<T>& value)
		{
			if (pWrapper == NULL) pWrapper = new ObjectWrapper(value);
		}
		
		inline_ ReturnValue<T>& GetValue()
		{
			ASSERT(pWrapper != NULL);
			return pWrapper->m_Value;
		}
		inline_ ReturnValue<T>* GetValuePtr()
		{
			ASSERT(pWrapper != NULL);
			return &pWrapper->m_Value;
		}
		
		inline_ void DestroyWrapper() 
		{ 
			if (pWrapper != NULL) 
				delete pWrapper;
		}
};

template <class T>
class CV8WithOutLocalWrapperTemplate
{
	class ObjectWrapper
	{
		public:
			T m_Object;
		public:
			inline_ ObjectWrapper(const T& that):m_Object(that) {}
			inline_ ~ObjectWrapper(){}
	};
	
	private:
		ObjectWrapper* pWrapper;

	public:
		inline_ CV8WithOutLocalWrapperTemplate() { pWrapper = NULL; }
		inline_ ~CV8WithOutLocalWrapperTemplate() { DestroyWrapper(); }
		
		inline_ void CreateObject(const T& value)
		{
			if (pWrapper == NULL) pWrapper = new ObjectWrapper(value);
		}
		
		inline_ T& GetObject()
		{
			ASSERT(pWrapper != NULL);
			return pWrapper->m_Object;
		}
		inline_ T* GetObjectPtr()
		{
			ASSERT(pWrapper != NULL);
			return &pWrapper->m_Object;
		}
		
		inline_ void DestroyWrapper() 
		{ 
			if (pWrapper != NULL) 
				delete pWrapper;
		}
};

#endif
